package com.john.blog.common.utils;

import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.john.blog.common.vo.FtpConfig;

/**
 * ftp上传下载工具类
 * 
 * @author JiangGengchao
 * @date 2018年3月11日
 */
public class FtpUtil {

    private static transient Logger log = LoggerFactory.getLogger(FtpUtil.class);

    /**
     * 向FTP服务器上传文件
     * 
     * @param ftpConfig
     * @param filename
     * @param input
     * @return 成功返回true，否则返回false
     */
    public static boolean uploadFile(FtpConfig ftpConfig, String filename, InputStream input) {
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(ftpConfig);
            // 切换到上传目录
            if (setDirectory(ftpClient, ftpConfig.getDefaultRemoteDir())) {
                // 上传文件
                log.info("===============开始上传文件：" + filename + "=====================");
                if (ftpClient.storeFile(filename, input)) {
                    log.debug("===============上传成功=====================");
                    return true;
                }
            }
            log.debug("===============上传失败=====================");
            return false;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return false;
        } finally {
            disconnect(ftpClient);
        }
    }

    /**
     * 通过文件name删除文件
     * 
     * @param ftpConfig
     * @param fileName
     * @return
     */
    public static boolean deleteFile(FtpConfig ftpConfig, String fileName) {
        FTPClient ftpClient = null;
        try {
            ftpClient = connect(ftpConfig);
            if (setDirectory(ftpClient, ftpConfig.getDefaultRemoteDir())) {
                String[] fileNamesOnServer = ftpClient.listNames();
                if (DetectUtils.notEmpty(fileName) && DetectUtils.notEmpty(fileNamesOnServer)) {
                    for (int i = 0; i < fileNamesOnServer.length; i++) {
                        if (fileName.equals(fileNamesOnServer[i])) {
                            ftpClient.dele(fileNamesOnServer[i]);
                            log.info("从ftp:" + ftpConfig.getIp() + "删除文件:" + fileNamesOnServer[i]);
                        }
                    }
                }
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("error", e);
            return false;
        } finally {
            disconnect(ftpClient);
        }
    }

    /**
     * 递归创建目录
     * 
     * @param ftpClient
     * @param dir
     * @return
     * @throws IOException
     */
    private static boolean setDirectory(FTPClient ftpClient, String dir) throws Exception {
        log.debug("===============设置工作空间：" + dir + "=====================");
        if (!ftpClient.changeWorkingDirectory(dir)) {
            // 如果目录不存在创建目录
            String[] dirs = dir.split("/");
            String tempPath = "";
            for (String tempDir : dirs) {
                if (DetectUtils.isEmpty(tempDir)) {
                    continue;
                }
                tempPath += "/" + dir;
                if (!ftpClient.changeWorkingDirectory(tempPath)) {
                    if (!ftpClient.makeDirectory(tempPath)) {
                        return false;
                    } else {
                        ftpClient.changeWorkingDirectory(tempPath);
                    }
                }
            }
        }
        // 设置上传文件的类型为二进制类型
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        return true;
    }

    /**
     * 连接获取FTPClient
     * 
     * @param ftpConfig
     * @return
     * @throws Exception
     */
    private static FTPClient connect(FtpConfig ftpConfig) throws Exception {
        FTPClient ftpClient = null;
        try {
            log.debug("===============连接ftp:" + ftpConfig.getIp() + "=====================");
            ftpClient = new FTPClient();
            ftpClient.setControlEncoding(ftpConfig.getEncoding());
            ftpClient.connect(ftpConfig.getIp(), ftpConfig.getPort());
            ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
            ftpClient.enterLocalPassiveMode();
            int returnCode = ftpClient.pasv();
            returnCode = ftpClient.getReplyCode();
            ftpClient.setDataTimeout(30000);
            if (!FTPReply.isPositiveCompletion(returnCode)) {
                if (log.isDebugEnabled()) {
                    log.debug("FTP server refused connection.returnCode=" + returnCode);
                }
                throw new Exception("FTP server refused connection.returnCode=" + returnCode);
            }
            if (log.isDebugEnabled()) {
                log.debug("connected to FTP server. ip=" + ftpConfig.getIp() + ", port=" + ftpConfig.getPort());
            }
            return ftpClient;
        } catch (Exception e) {
            log.error("username=" + ftpConfig.getUsername() + ", password=" + ftpConfig.getPassword() + ", serverIp=" + ftpConfig.getIp() + ", port=" + ftpConfig.getPort() + ", encoding="
                    + ftpConfig.getEncoding(), e);
            if (null != ftpClient) {
                try {
                    ftpClient.disconnect();
                } catch (Exception e1) {
                    log.error("ftpClient断开失败;" + e1.getMessage(), e1);
                }
                ftpClient = null;
            }
            throw new Exception(e);
        }
    }

    /**
     * 优化下： ftp.isConnected最好要写在finally里面，不要直接写在ftp.logout()后面, 这样子写会有很大的隐患。
     * 
     * @author TaoPingPing
     * @param ftpClient
     */
    private static void disconnect(FTPClient ftpClient) {
        if (null != ftpClient) {
            try {
                ftpClient.logout();
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            } finally {
                if (ftpClient.isConnected()) {
                    try {
                        ftpClient.disconnect();
                    } catch (IOException ioe) {
                    }
                }
                ftpClient = null;
            }
        }
    }

}
